package com.example.rabbitmq.service;

import com.example.rabbitmq.domain.User;
import org.springframework.amqp.core.AmqpAdmin;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.FanoutExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * 消息生产者服务类
 * 负责向RabbitMQ交换机发送消息，实现基于发布/订阅模式的消息生产逻辑
 */
@Service // 标识为服务层组件，由Spring容器管理
public class MessageProducerService {

    // 声明AmqpAdmin对象（当前注释掉，用于动态创建交换机、队列和绑定关系）
    // private AmqpAdmin amqpAdmin;

    /**
     * 注入RabbitTemplate
     * 用于与RabbitMQ交互，发送消息到指定交换机
     */
    @Autowired
    private RabbitTemplate rabbitTemplate;

    /**
     * 构造方法（当前注释掉）
     * 通过AmqpAdmin动态声明交换机、队列和绑定关系
     * 适用于需要在应用启动时自动创建RabbitMQ组件的场景
     */
    /*@Autowired
    public MessageProducerService(AmqpAdmin amqpAdmin, RabbitTemplate rabbitTemplate) {
        this.amqpAdmin = amqpAdmin;
        this.rabbitTemplate = rabbitTemplate;
        // 声明Fanout类型交换机
        this.amqpAdmin.declareExchange(new FanoutExchange("pub/sub.exchange"));
        // 声明邮件队列和短信队列
        this.amqpAdmin.declareQueue(new Queue("email.queue"));
        this.amqpAdmin.declareQueue(new Queue("sms.queue"));
        // 绑定队列到交换机（Fanout模式下路由键为空）
        this.amqpAdmin.declareBinding(new Binding("email.queue", Binding.DestinationType.QUEUE, "pub/sub.exchange", "", null));
        this.amqpAdmin.declareBinding(new Binding("sms.queue", Binding.DestinationType.QUEUE, "pub/sub.exchange", "", null));
    }*/

    /**
     * 发布用户信息到RabbitMQ的发布/订阅交换机
     * 通过RabbitTemplate将User对象发送到指定交换机，由交换机广播到所有绑定的队列
     * @param user 要发送的用户对象（会被自动序列化为JSON）
     */
    public void psubPublisher(User user) {
        // 发送消息到指定交换机
        // 参数1：交换机名称（pub/sub.exchange）
        // 参数2：路由键（Fanout模式下为空字符串，不影响消息路由）
        // 参数3：要发送的消息内容（User对象）
        this.rabbitTemplate.convertAndSend("pub/sub.exchange", "", user);
    }

    /**
     * 基于路由模式（Routing）发送消息
     * 该方法通过指定交换机和路由键，将消息发送到符合路由规则的队列
     * 路由 路由模式特点：
     * 1. 使用Direct类型交换机，根据消息的路由键（Routing Key）精确匹配队列
     * 2. 只有绑定键（Binding Key）与路由键完全匹配的队列才能接收消息
     * 3. 支持按消息级别/类型进行定向分发（如日志系统中的ERROR、INFO级别）
     *
     * @param level 消息级别（用于动态生成路由键，如"error"、"info"）
     * @param message 要发送的消息内容
     */
    public void routingPublisher(String level, String message) {
        // 使用RabbitTemplate发送消息到指定交换机
        // 参数1：交换机名称（"routing.exchange"，需为Direct类型）
        // 参数2：路由键（动态拼接为"routingkey." + level，如"routingkey.error"）
        // 参数3：消息内容（字符串类型）
        this.rabbitTemplate.convertAndSend("routing.exchange", "routingkey." + level, message);
    }

    /**
     * 基于主题模式（Topic）发送消息
     * 主题模式是路由模式的扩展，支持通过通配符匹配路由键，实现更灵活的消息路由
     * 主题模式特点：
     * 1. 使用Topic类型交换机，通过路由键（Routing Key）的通配符匹配绑定键（Binding Key）
     * 2. 路由键通常由多个单词组成，以点号（.）分隔（如"order.create"、"user.login"）
     * 3. 支持两种通配符：
     *    - *：匹配一个单词
     *    - #：匹配零个或多个单词
     *
     * @param routingkey 消息的路由键（如"log.error"、"user.info"），用于匹配队列的绑定键
     * @param message 要发送的消息内容
     */
    public void topicPublisher(String routingkey, String message) {
        // 使用RabbitTemplate发送消息到Topic类型交换机
        // 参数1：交换机名称（"topic.exchange"，需为Topic类型）
        // 参数2：路由键（用于与队列的绑定键进行通配符匹配）
        // 参数3：消息内容（字符串类型）
        this.rabbitTemplate.convertAndSend("topic.exchange", routingkey, message);
    }
}